MMBasic Source Formatter ver 2.3 20/4/2013
==========================================

Format.bas is a program to indent lines of MMBasic source code in order to highlight the program structure.


Four methods to invoke
======================

1. Implied Run Command
----------------------
MMBasic ver 4.3A allows you to invoke a program from the prompt with the program name followed by a parameter list. The parameter list is passed to the program in the Read-Only Variable MM.CMDLINE$.

At the MMBasic prompt type:

	FORMAT InFileName[.bas] OutFileName[.bas] [Indent] [/P]

Where:
	InFileName  is the program source to be formatted.
	OutFileName is the result of formatting.
		    OutFileName must not be the same as InfileName.
	Indent      is the optional number of characters to indent at each level (default 2)
	/P          is an optional switch to list the output, pausing each screenful

	If an extension is not provided on the file names, Format inserts .bas.

If you prefer, you can separate parms with either a blank or a comma so this is also valid:

	FORMAT InFileName[.bas],OutFileName[.bas],[Indent],[/P]


2. Chaining from another program
--------------------------------
If you Chain to Format, you can either
  - create a file FORMAT.DAT containing the parameters (see method 3 below) or 
  - let Format prompt for all four parameters as if you had just used method 4 below or 
  - you can pass the 4 parameters to it in a variable CMDParm$. 

To use the latter, transfer control to Format using:

	CMDParm$ = "InFileName[.bas] OutFileName[.bas] [Indent] [/p]"
	CHAIN "FORMAT.BAS"

Format uses about 55kB of memory, so if your Chaining program uses large arrays, you may need to ERASE them before chaining to Format.


3. Config file FORMAT.DAT
-------------------------
If Format doesn't find the parameter list in MM.CMDLINE$ or CMDParm$, then it looks for a file FORMAT.DAT. This file contains a single line in the same format as the parameter list for the Implied RUN Command. i.e.

	InFileName[.bas] OutFileName[.bas] [Indent] [/P] or
	InFileName[.bas],OutFileName[.bas],[Indent],[/P]


4. "Normal" invocation
----------------------
You can invoke Format by typing RUN "FORMAT[.BAS]" at the command prompt and Format will prompt for the four parameters.


Formatting Rules
================
FORMAT's standard set of rules:

	- Lines starting with a Label are aligned to the left margin
	  as are SUB, END SUB, FUNCTION and END FUNCTION.

	- The first non-label line is indented to the first level.

	- Lines following a single line IF, DO and FOR are not further indented.

	- Multiline DO and FOR have their respective LOOP and NEXT aligned.
	  Intervening lines are indented one level.

	- The NEXT that closes multiple levels of FOR is aligned under the first FOR.

	- Multiline IF statements have their ELSE, ELSEIF and ENDIF aligned
	  under the relevant IF. Intervening statements are indented one level.

	- Nesting increases the indent one level.

	- For numbered programs, the line number is left aligned and the rest of the source
	  uses the length of the longest number plus one as the left margin.

	- Other than setting the indent, the source line is not altered.

	- No attempt is made to check or report program errors.


Implementaion Details
=====================
Initialisation gets input and output file names, indent and pause. The input file is checked to make sure it exists and if the output exists, the user is asked to confirm that it be used. The program doesn't allow the output to overwrite the input in case of a power or equipment failure.

The program first runs through the input file looking for line numbers, storing the length of the longest line number. If found, the line numbers are aligned at the left margin and the margin for the rest of the code set at the longest line number plus one space..

Each line is read in turn and, working on a copy of the line, the indent of the current and next line is found. The original line is then stripped of any leading spaces, indented with an appropriate number of blanks and written out. If the Pause switch has been set, the program copies the formatted source to the screen, pausing at each screenful for the user to press a key.

Each line is examined and processed in turn, writing it out when completed.

The first text encountered on the line is tested to see if it is, in order of precedence:

- A comment or end-of-line.
- SUB, END SUB, FUNCTION, END FUNCTION
- DO
- LOOP
- FOR
- NEXT
- IF... THEN
- ELSEIF
- ELSE
- Label

Appropropriate indenting action is taken if one of these commands is found at the start of a line. The line is then searched for colons and indenting adjusted if another of these commands is found.

Lines starting with SUB, END SUB, FUNCTION, END FUNCTION or a label are aligned to the left margin.

Lines starting with DO, FOR and IF signal that the following line should be indented one level.

Lines starting with LOOP, NEXT, ELSEIF and ELSE are set to one less level of indent than the previous line. If the NEXT is followed by multiple loop variables, then an indent is removed for each variable.

If a LOOP or NEXT appears on the same line as it's DO and FOR, then the level change for the next line is cancelled.

If an IF... THEN is followed by a statement (and optional ELSE), then it is treated as a single-line-if and the level change for the next line cancelled.


Tables
------

Two tables, populated by DATA statements, are used to help parse a line:

- One contains reserved words which can be followed immediately by a colon. e.g. PRINT: This is used to prevent these words from being incorrectly identified as a label.

- The other table contains a list of operators which is used to differenitate between a label and any other statement. Contiguous text containing an operator cannot be a label. e.g. A=B: is not a label.


Change Log
==========
20/4/2013 V2.3
- When a file has line numbers followed by one or more spaces and a colon, the colon is moved adjacent to the line number. This mod was triggerd by MMPREY.BAS in MMLib which exhibits this condition.
- If a line starts with a colon (after the optional line number and its optional colon) then it is removed.
- e.g. "1234   : Statement"   is changed to 
       "1234: Statement". 

       "1234:  :Statement"   is changed to 
       "1234: Statement".
 
       "   :Statement :Statement" is changed to
       "   Statement :Statement"
- Fixed a problem when nested FOr/NEXT loops appear on a single line and one of the NEXT statements terminates more than one level.

Hugh Buckle

